# coding=utf-8
from scipy.optimize import minimize
import math as m
import numpy as np
def getpoint(a, b, c, d):
    k=10
    alpha = 0.88
    beta = 0.88
    theta = 2.25
    delta = 0.61
    gamma = 0.69
    p=1/k
    pi1 = (p ** gamma) / (p ** gamma + (1 - p) ** gamma) ** (1 / gamma)
    pi2 = (p ** delta) / (p ** delta + (1 - p) ** delta) ** (1 / delta)
    hesitate = b+c-a-d
    point = []
    point1 = []
    step = (b - a) / (k - 1)
    step1 = (d - c) / (k - 1)
    for i in range(k):
        point.append(a + step * i)
    for i in range(k):
        point1.append(c + step1 * i)
    average = 0.5
    prospect = [0 for i in range(k)]  # 取中间值为参考点
    d1 = [0 for i in range(k)]
    p = 1 / k
    for i in range(k):
        d1[i] = point[i] - average
        if (d1[i] >= 0):
            prospect[i] = (d1[i] ** alpha)*pi1
        if (d1[i] < 0):
            prospect[i] = -1 * theta * ((-1 * d1[i]) ** beta)*pi2
            # 获得每个点对应前景价值
    prospect3 = [0 for i in range(k)]  # 取中间值为参考点
    d3 = [0 for i in range(k)]
    for i in range(k):
        d3[i] = point1[i] - average
        if d3[i] >= 0:
            prospect3[i] = 1* (d3[i] ** alpha)*pi1
        if d3[i] < 0:
            prospect3[i] =-1* ((-1 * d3[i]) ** beta) * theta*pi2
    weight1 = []
    min1 =-1*theta*((0.5)**beta)*pi2
    p1 = [0 for i in range(k)]
    for i in range(k):
        p1[i] = prospect[i] - min1
    for i in range(k):
        sum1 = sum(p1)
        if (sum1 == 0):
            weight1.append(1 / k)
        else:
            weight1.append(p1[i] / sum1)
    weight3 = []
    for i in range(k):
        weight3.append(weight1[i])
    weight5 = []
    min2 = -1*theta*((0.5)**beta)*pi2
    p4 = [0 for i in range(k)]
    for i in range(k):
        p4[i] = prospect3[i] - min2
    for i in range(k):
        sum4 = sum(p4)
        if (sum4 == 0):
            weight5.append(1 / k)
        else:
            weight5.append(p4[i] / sum(p4))
    weight6 = []
    for i in range(k):
        weight6.append(weight5[i])
    value = []
    value1 = []
    value2 = []
    for i in range(k):
        value1.append(weight3[i] * point[i])
        value2.append(weight6[i] * point1[i])
    u=sum(value1)
    v=sum(value2)
    score =-1*m.log((m.exp(2*(u-v))/(3-(b+d+a+c)))**(1/2),np.exp(1))
    # score = m.log((m.exp(2 * (u - v)) / (1+1-u-v)) ** (1 / 2), np.exp(1))
    return score
# 计算  y 的最大值  x1,x2,x3,x4的范围都在0到1之间

def fun(args):
    a, b, c, d = args
    #lambda x后面的目标函数不加负号是求最小值 加负号是求最大值(但是结果要去除负号)
    v = lambda x:getpoint(a * x[0] ,b * x[1] ,c * x[2] ,d * x[3])
    # v = lambda x: ((b*x[1]+d*x[3])**2-(a*x[0]+c*x[2])**2)
    # v = lambda x: -(m.log(a * x[0] + b * x[1] + c * x[2] + d * x[3] + 1) + (a * x[0] - b * x[1]) ** 2 + (c * x[2] - d * x[3]) ** 2 + (a * x[0] + b * x[1] - c * x[2] - d * x[3]) * m.log(3) / 2) / (2 * m.log(3))

    return v

def con(args):
    # 约束条件 分为eq 和ineq
    # eq表示 函数结果等于0 ； ineq 表示 表达式大于等于0
    x1min, x1max, x2min, x2max, x3min, x3max,x4min, x4max = args
    cons = ({'type': 'ineq', 'fun': lambda x: x[0] - x1min},# 约束条件中0<x1<0
            {'type': 'ineq', 'fun': lambda x: -x[0] + x1max},
            {'type': 'ineq', 'fun': lambda x: x[1] - x2min},
            {'type': 'ineq', 'fun': lambda x: -x[1] + x2max},
            {'type': 'ineq', 'fun': lambda x: x[2] - x3min},
            {'type': 'ineq', 'fun': lambda x: -x[2] + x3max},
            {'type': 'ineq', 'fun': lambda x: x[3] - x4min},
            {'type': 'ineq', 'fun': lambda x: -x[3] + x4max},
            {'type': 'ineq', 'fun': lambda x: x[1] - x[0]},  # 约束条件中x2-x1>0
            {'type': 'ineq', 'fun': lambda x: x[3] - x[2]},  # 约束条件中x4-x3>0
            {'type': 'ineq', 'fun': lambda x: x[0]**2 + x[2]**2},  #约束条件中x1**q-x3**q>0 q=2
            {'type': 'ineq', 'fun': lambda x: 1-(x[0] ** 2 + x[2] ** 2)}#约束条件中1-(x1**q-x3**q)>0 q=2
            # {'type': 'ineq', 'fun': lambda x: 1 - (x[0] ** 2 + x[2] ** 2)}  # 约束条件中1-(x1**q-x3**q)>0 q=2
            )

    return cons


if __name__ == "__main__":
    # 定义常量值
    args = (1, 1, 1, 1)  # a,b,c,d
    # 设置参数范围/约束条件
    args1 = (0, 1, 0, 1, 0, 1, 0, 1)  # x1min, x1max, x2min, x2max, x3min, x3max, x4min, x4max
                                      #即约束函数中x1,x2,x3,x4 的取值范围为(0,1)
    cons = con(args1)
    # 设置初始猜测值
    x0 = np.asarray((0.5, 0.5, 0.5,0.5))

    res = minimize(fun(args), x0, method='SLSQP', constraints=cons)

    print(res)
    print(f'y等于{round(res.fun,4)}')
    print(res.success)
    point=round(res.x[0],4),round(res.x[1],4),round(res.x[2],4),round(res.x[3],4)
    print(f'对应点为：{point}')